package spindles.gwt.client;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.SourcesTableEvents;
import com.google.gwt.user.client.ui.TableListener;
import com.google.gwt.user.client.ui.Widget;

public class DetailsTable extends Composite implements TableListener,
		ClickListener, Publisher {

	private int visibleRowsCount = 2;

	private HTML countLabel = new HTML();

	private HTML newerButton = new HTML(
			"<a href='javascript:;'>&lt; previous</a>", true);

	private HTML olderButton = new HTML(
			"<a href='javascript:;'>next &gt;</a>", true);

	private int startIndex, selectedRow = -1;

	private FlexTable table = new FlexTable();

	private HorizontalPanel navBar = new HorizontalPanel();

	private TableData tableData;
	
	private List subscribers = new ArrayList();

	public DetailsTable(TableData tableData) {
		this.tableData = tableData;
		
		// Setup the table.
		table.setCellSpacing(0);
		table.setCellPadding(0);
		table.setWidth("100%");

		// Hook up events.
		table.addTableListener(this);
		newerButton.addClickListener(this);
		olderButton.addClickListener(this);

		// Create the 'navigation' bar at the upper-right.
		HorizontalPanel innerNavBar = new HorizontalPanel();
		navBar.setStyleName("spindles-ListNavBar");
		innerNavBar.add(newerButton);
		innerNavBar.add(countLabel);
		innerNavBar.add(olderButton);

		navBar.setHorizontalAlignment(HorizontalPanel.ALIGN_RIGHT);
		navBar.add(innerNavBar);
		navBar.setWidth("100%");

		initWidget(table);
		setStyleName("spindles-List");

		initTable();
		update();
	}
	
	public void setTableData(TableData td){
		this.tableData = td;		
		update();
	}
	
	public void onCellClicked(SourcesTableEvents sender, int row, int cell) {
		// Select the row that was clicked (-1 to account for header row).
		if (row > 0) {
			selectRow(row - 1);
		}
	}

	public void onClick(Widget sender) {
		if (sender == olderButton) {
			// Move forward a page.
			startIndex += visibleRowsCount;
			if (startIndex >= tableData.getRowCount()) {
				startIndex -= visibleRowsCount;
			} else {
				styleRow(selectedRow, false);
				selectedRow = -1;
				update();
			}
		} else if (sender == newerButton) {
			// Move back a page.
			startIndex -= visibleRowsCount;
			if (startIndex < 0) {
				startIndex = 0;
			} else {
				styleRow(selectedRow, false);
				selectedRow = -1;
				update();
			}
		}
	}
	
	public void addSubscriber(Subscriber subscriber){
		subscribers.add(subscriber);
	}
	

	private void initTable() {
		// Create the header row.
		String headers[] = tableData.getFieldNames();
		
		int idx = 0;
		for (; idx < headers.length; idx++){
			table.setText(0, idx, headers[idx]);
		}		
		table.setWidget(0, idx, navBar);
		table.getRowFormatter().setStyleName(0, "spindles-ListHeader");

		// Initialize the rest of the rows.
		for (int i = 0; i < visibleRowsCount; ++i) {
			for (; idx < headers.length; idx++){
				table.setText(i + 1, idx, "");				
				table.getCellFormatter().setWordWrap(i + 1, idx, false);			
			}			
			table.getFlexCellFormatter().setColSpan(i + 1, idx - 1, 2);
		}
	}

	/**
	 * Selects the given row (relative to the current page).
	 * 
	 * @param row the row to be selected
	 */
	private void selectRow(int row) {
		TableData.Row item = tableData.getRow(startIndex + row);
		if (item == null) {
			return;
		}

		styleRow(selectedRow, false);
		styleRow(row, true);
		
		selectedRow = row;
		
		notifySubscribers();
	}

	private void styleRow(int row, boolean selected) {
		if (row != -1) {
			if (selected) {
				table.getRowFormatter().addStyleName(row + 1,
						"spindles-SelectedRow");
			} else {
				table.getRowFormatter().removeStyleName(row + 1,
						"spindles-SelectedRow");
			}
		}
	}
	
	private void setVisibleRowsCount(int rowsCount){
		if(rowsCount > 10){
			this.visibleRowsCount = 10;
		} else {
			this.visibleRowsCount = rowsCount;
		}	
	}

	public void update() {
		int previousVisibleRowsCount = visibleRowsCount;
		
		// Update the older/newer buttons & label.
		int count = tableData.getRowCount();		
		
		setVisibleRowsCount(count);
		
		int max = startIndex + visibleRowsCount;
		if (max > count) {
			max = count;
		}

		newerButton.setVisible(startIndex != 0);
		olderButton.setVisible(startIndex + visibleRowsCount < count);
		countLabel.setText("" + (startIndex + 1) + " - " + max + " of " + count);

		// Show the selected rows.
		int i = 0;
		for (; i < visibleRowsCount; ++i) {
			// Don't read past the end.
			if (startIndex + i >= tableData.getRowCount()) {
				break;
			}

			TableData.Row item = tableData.getRow(startIndex + i);

			// Add a new row to the table			
			for (int idx = 0; idx < tableData.getFieldCount(); idx++){
				table.setText(i + 1, idx, item.getValue(idx));
			}		
		}

		// Clear any remaining slots.
		for (; i < previousVisibleRowsCount; ++i) {
			
			for (int idx = 0; idx < tableData.getFieldCount(); idx++){
				table.setHTML(i + 1, idx, "&nbsp;");
			}		
			
		}

		// Select the first row if none is selected.
		if (selectedRow == -1) {
//			selectRow(0);
		}
	}

	public void notifySubscribers() {
		
		for (int i = 0; i < subscribers.size(); i++) {
			Subscriber s = (Subscriber)subscribers.get(i);
			s.update(tableData.getRow(startIndex + selectedRow));
		}

	}
}
